/*

bvqx_srf_writeneighborsc.c  - create stream of neighbors for writing

FORMAT:       neistream = bvqx_srf_writeneighborsc(neighbors)

Input fields:

      neighbors   Nx2 neighbors cell array

Output fields:

      neistream   1xS uint32 stream with neighbor information

% Version:  v0.7g
% Build:    9101522
% Date:     Oct-15 2009, 10:38 PM CEST
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

 */

#include "mex.h"
#include "matrix.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

    int nv = 0, nv2 = 0, ne = 0, skip = 0, nn, vn = 0, vc;
    int *nnei, *nneip, *out;
    double dnv = 0.0;
    const int *ind;
    const double *din;
    const mxArray *cell;
    
    /* argument check */
    if (nrhs != 1 || nlhs != 1)
		mexErrMsgTxt("Bad number of input/output arguments.");
    if (!mxIsCell(*prhs) ||
        (mxGetNumberOfDimensions(*prhs) != 2))
		mexErrMsgTxt("Input argument must be of type MxN cell.");
    ind = mxGetDimensions(*prhs);
    if (ind[1] != 2)
        mexErrMsgTxt("Cell array must be Vx2 sized.");
    nv = *ind;
    
    /* allocate temporary memory for number of neighbors per vertex */
    nneip = nnei = (int *) mxCalloc(nv, sizeof(int));
    if (nneip == NULL)
        mexErrMsgTxt("Error allocating temporary array.");
    
    /* parse over second column of cell array */
    for (nv2 = nv + nv, vc = nv; vc < nv2; ++vc) {
        cell = (const mxArray*) mxGetCell(*prhs, vc);
        if (cell == NULL) {
            mxFree(nnei);
            mexErrMsgTxt("Invalid neighbors cell array.");
        }
        if (mxGetClassID(cell) != mxDOUBLE_CLASS) {
            mxFree(nnei);
            mexErrMsgTxt("Invalid neighbors cell array.");
        }
        nn = (int) mxGetNumberOfElements(cell);
        if ((nn < 1) || (nn > 36)) {
            mxFree(nnei);
            mexErrMsgTxt("Invalid neighbors cell array.");
        }
        *nneip++ = nn;
        ne += nn + 1;
    }
    
    /* prepare output */
    *plhs = mxCreateNumericMatrix(1, ne, mxUINT32_CLASS, mxREAL);
    if (*plhs == NULL) {
        mxFree(nnei);
        mexErrMsgTxt("Error creating neighbors stream.");
    }
    out = (int *) mxGetPr(*plhs);
    if (out == NULL) {
        mxFree(nnei);
        mexErrMsgTxt("Error allocating neighbors stream memory.");
    }
    
    /* parse over second column of cell array again */
    nneip = nnei;
    for (vc = nv; vc < nv2; ++vc) {
        
        /* get number of neighbors for vertex */
        nn = *nneip++;
        
        /* put into output first */
        *out++ = nn;
        
        /* get pointer to cell content */
        din = mxGetPr((const mxArray*) mxGetCell(*prhs, vc));

        /* copy numbers */
        for (; nn > 0; --nn)
            *out++ = (int) (*din++ - 1);
    }

    /* free memory */
    mxFree(nnei);
}
